﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using myBoard.Framework;
using System.Reflection;
using Webnet.BO;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using Webnet.BO.ConfigSteps;
using myBoard.Framework.Controls.Navigation;
using System.Diagnostics;
using myBoard.Framework.Effects;
using System.Windows.Media.Effects;

namespace Webnet
{
    public partial class MainControl : IMagnet, ICanResize, IFlip, ICanDrag, IRequiresStorage
    {
        private bool _canResize = false;
        private bool _canDrag = false;
        private bool _effectsApplied = false;
        Cjc.ChromiumBrowser.WebBrowser _webBrowser;
        Storyboard _showBrowserSB;
        Storyboard _hideBrowserSB;
        Storyboard _resizeSB;
        Storyboard _loadingModeSB;
        Storage _storage;
        Settings _settings = null;
        bool _hasContent;
        bool _hasAlreadyFinishedLoadingOnce;

        /// <summary>
        /// Constructor
        /// </summary>
        public MainControl()
        {
            this.InitializeComponent();
            _webBrowser = new Cjc.ChromiumBrowser.WebBrowser();
            MouseLeftButtonDown += new MouseButtonEventHandler(MainControl_MouseLeftButtonDown);
            MouseLeftButtonUp += new MouseButtonEventHandler(MainControl_MouseLeftButtonUp);
            _configBt.Click += new EventHandler(_configBt_Click);
            this.Loaded += new RoutedEventHandler(MainControl_Loaded);
            _showBrowserSB = this.Resources["ShowBrowser"] as Storyboard;
            _hideBrowserSB = this.Resources["HideBrowser"] as Storyboard;
            _resizeSB = this.Resources["Resize"] as Storyboard;
            _loadingModeSB = this.Resources["LoadingMode"] as Storyboard;
            this.SizeChanged += new SizeChangedEventHandler(MainControl_SizeChanged);
            _webBrowser.FinishLoading += new EventHandler(WebBrowser_FinishLoading);
            _webBrowser.BeginLoading += new EventHandler<Cjc.ChromiumBrowser.WebBrowser.LoadingEventArgs>(WebBrowser_BeginLoading);
        }

        void WebBrowser_BeginLoading(object sender, Cjc.ChromiumBrowser.WebBrowser.LoadingEventArgs e)
        {
            this.BeginStoryboard(_loadingModeSB);
        }

        private void RemoveAllEffects()
        {
            background.Effect = null;
            _browserContainer.Effect = null;
            this.Effect = null;
            _info.Effect = null;
            _effectsApplied = false;
        }

        private void AddAllEffects()
        {
            background.Effect = new LightStreakEffect() { Scale = 0.35, Direction = new Vector(0.5, 1) };
            _browserContainer.Effect = new LightStreakEffect() { Scale = 10};
            _info.Effect = new DropShadowEffect() { BlurRadius = 13, ShadowDepth = 4 };
            this.Effect = new DropShadowEffect() { BlurRadius = 12, ShadowDepth = 4 , Direction=321, Opacity = 0.395};
            _effectsApplied = true;
        }

        void MainControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (_settings != null && _canResize)
            {
                _settings.DefaultSize = new Size(this.ActualWidth, this.ActualHeight);
            } 
        }

        void MainControl_Loaded(object sender, RoutedEventArgs e)
        {
            _configExplorer.BreadcrumbEntities.CollectionChanged += (a,b) =>
                {
                    foreach (IBreadcrumbExplorerEntity entity in _configExplorer.BreadcrumbEntities)
                    {
                        StepBase step = entity as StepBase;
                        if (step != null)
                        {
                            step.WizardCompleted -= new EventHandler<Settings>(step_WizardCompleted);
                            step.WizardCompleted += new EventHandler<Settings>(step_WizardCompleted);
                            step.WizardCanceled -= new EventHandler(step_WizardCanceled);
                            step.WizardCanceled += new EventHandler(step_WizardCanceled);
                        }
                    }
                };

            SourceType sourceType = new SourceType();
            sourceType.Name = "Source type";
            _configExplorer.FirstEntity = sourceType;
            sourceType.RestoreSettings(_settings);

            _browserContainer.Child = _webBrowser;

            if ((_settings.ContentType == BrowserContentType.Html && !string.IsNullOrEmpty(_settings.Html)) ||
                (_settings.ContentType == BrowserContentType.Url && !string.IsNullOrEmpty(_settings.Url)))
            {
                //_webBrowser.LoadHtml(_settings.Html);
                DispatcherTimer delayTimer = new DispatcherTimer();
                delayTimer.Interval = new TimeSpan(0, 0, 1);
                delayTimer.Tick += new EventHandler(Delay_Tick);
                delayTimer.Start();               
            }
        }

        void step_WizardCanceled(object sender, EventArgs e)
        {
            if (FlipRequested != null)
                FlipRequested(MagnetSides.Front);
        }

        void step_WizardCompleted(object sender, Settings s)
        {
            if (FlipRequested != null)
                FlipRequested(MagnetSides.Front);

            _settings.DefaultSize = new Size();
            SaveState();
            //let's wait for the flip animation to be completed
            DispatcherTimer delayTimer = new DispatcherTimer();
            delayTimer.Interval = new TimeSpan(0, 0, 1);
            delayTimer.Tick += new EventHandler(Delay_Tick);
            delayTimer.Start();
        }

        void Delay_Tick(object sender, EventArgs e)
        {
            AddAllEffects();
            if (_hasContent)
            {
                this.BeginStoryboard(_hideBrowserSB);
            }

            DispatcherTimer timer = sender as DispatcherTimer;            
            if(timer!=null)
                timer.Tick -= new EventHandler(Delay_Tick);

            if (_settings.ContentType == BrowserContentType.Html)
                LoadHtml();
            else
                LoadUrl();
            
            _hasContent = true;
            
        }

        void LoadHtml()
        {
            string htmlCode = _settings.Html;            
            string requestId = string.Empty;
            if ((!htmlCode.Contains("<html>") && !htmlCode.Contains("</html>")) || htmlCode.StartsWith("<script "))
            {
                htmlCode = htmlCode.Insert(0, @"<html><head><style>html, body {  height: 100%;  overflow: hidden;}</style></head><body bgcolor=""#0F0F0F"" leftmargin=""0"" topmargin=""0"" marginwidth=""0"" marginheight=""0"">");
                htmlCode += "</body><html/>";

                Connector.WebServer.StartWebServer();
                requestId = Guid.NewGuid().ToString();
                Connector.WebServer.SetResponse(requestId, htmlCode);
            }

            AutoResize(htmlCode);
            if (string.IsNullOrEmpty(requestId))
                _webBrowser.LoadHtml(htmlCode);
            else
                _webBrowser.Source = string.Format("http://localhost:8081/{0}", requestId);
            _info.Text = "loading ...";            
        }

        void WebBrowser_FinishLoading(object sender, EventArgs e)
        {
            if (_hasAlreadyFinishedLoadingOnce)
            {                
                if (_settings != null && _settings.ContentType == BrowserContentType.Html)
                {
                    //Most html tags are flash object which also needs to load, so lets wait a little more ...
                    DispatcherTimer delayTimer = new DispatcherTimer();
                    delayTimer.Interval = new TimeSpan(0, 0, 2);
                    delayTimer.Tick += (a, b) =>
                    {
                        delayTimer.Stop();
                        if (!_effectsApplied)
                            AddAllEffects();
                        this.BeginStoryboard(_showBrowserSB);
                    };
                    delayTimer.Start();
                }
                else
                {
                    if (!_effectsApplied)
                        AddAllEffects();
                    this.BeginStoryboard(_showBrowserSB);
                }
                _loadingModeSB.Stop();
            }
            _hasAlreadyFinishedLoadingOnce = true;
        }

        void AutoResize(string htmlCode)
        {
            #region By default we take the current magnet size

            double targetWidth = this.ActualWidth;
            double targetHeight = this.ActualHeight;

            #endregion

            #region if we can detect width and height in the HTML code, then we'll take that instead

            if (!string.IsNullOrEmpty(htmlCode))
            {
                HTMLTools htmlTools = new HTMLTools();
                int height = htmlTools.GetHtmlHeight(htmlCode, 0);
                int width = htmlTools.GetHtmlWidth(htmlCode, 0);

                if (height != -1)
                    targetHeight = height + (this.ActualHeight - _browserContainer.ActualHeight);

                if (width != -1)
                    targetWidth = width + (this.ActualWidth - _browserContainer.ActualWidth);
            }

            #endregion

            #region If we have de default size specified in the settings, let's take this

            if (_settings.DefaultSize.Height != 0)
                targetHeight = _settings.DefaultSize.Height;

            if (_settings.DefaultSize.Width != 0)
                targetWidth = _settings.DefaultSize.Width;

            #endregion
            

            foreach (Timeline timeline in _resizeSB.Children)
            {
                switch (timeline.Name)
                {
                    case "WidthAnimation":
                        DoubleAnimationUsingKeyFrames widthAnimation = timeline as DoubleAnimationUsingKeyFrames;
                        widthAnimation.KeyFrames[0].Value = targetWidth;
                        break;
                    case "HeightAnimation":
                        DoubleAnimationUsingKeyFrames heightAnimation = timeline as DoubleAnimationUsingKeyFrames;
                        heightAnimation.KeyFrames[0].Value = targetHeight;
                        break;
                }
            }
            _resizeSB.Completed += (a, b) =>
            {
                this.Width = targetWidth;
                this.Height = targetHeight;
                if (_configExplorer.BreadcrumbEntities.Count > 0)
                {
                    _configExplorer.Scroll(_configExplorer.FirstEntity, _configExplorer.BreadcrumbEntities[_configExplorer.BreadcrumbEntities.Count - 1]);
                }
            };
            _resizeSB.Begin(this);
        }

        void LoadUrl()
        {
            AutoResize(string.Empty);
            _webBrowser.Source = _settings.Url;
            _info.Text = "loading ...";
        }

        void _configBt_Click(object sender, EventArgs e)
        {
            //_configExplorer.Scroll(_configExplorer.BreadcrumbEntities[0], _configExplorer.BreadcrumbEntities[_configExplorer.BreadcrumbEntities.Count - 1]);
            RemoveAllEffects();
            if (FlipRequested != null)
                FlipRequested(MagnetSides.Back);
        }

        void MainControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _canResize = false;
            e.Handled = false;            
        }

        void MainControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (_resizeGrip.IsMouseOver)
                _canResize = true;
            
            if (_webBrowser.IsMouseOver)
                _canDrag = false;
            else
                _canDrag = true;

            e.Handled = false;
        }

        #region IMagnet Members

        /// <summary>
        /// This is your magnet name, it will be used in the magnets explorer.
        /// </summary>
        public string MagnetName
        {
            get
            {
                return "Webnet";
            }
        }

        /// <summary>
        /// You MUST specify a StoreID, it has to be unique for each magnet.
        /// Use "Tools" -> "Create GUID" -> "Registry Format" -> "Copy" to create a StoreID for your magnet
        /// </summary>
        public string StoreID
        {
            get
            {
                return "{EE2726DD-A0B7-4d88-8EB9-A87350EB9A6A}";
            }
        }

        /// <summary>
        /// myBoard will call this method when your magnet is about to be destroyed.
        /// Add all cleaning code here.
        /// </summary>
        public void Terminate()
        {
            _browserContainer.Child = null;
            _webBrowser.Dispose();
            _webBrowser = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        /// <summary>
        /// This should return the image you want to use for your magnet in the magnet explorer
        /// </summary>
        public BitmapImage Icon
        {
            get
            {
                Assembly asm = Assembly.GetExecutingAssembly();
                return ResourcesAccess.GetBitmapImageFromResource(asm, "Webnet.Images.icon.png");
            }
        }

        /// <summary>
        /// This should return the image you want your magnet morphs into when the user drag it out of the magnet explorer.
        /// </summary>
        public BitmapImage Thumbnail
        {
            get
            {
                Assembly asm = Assembly.GetExecutingAssembly();
                return ResourcesAccess.GetBitmapImageFromResource(asm, "Webnet.Images.thumb.png");
            }
        }

        #endregion

        #region ICanResize Members

        public bool CanResize()
        {
            return _canResize;
        }

        #endregion

        #region IFlip Members

        public event OnFlipRequested FlipRequested;

        public Panel GetBackSide()
        {
            return _back;
        }

        public Panel GetFrontSide()
        {
            return _front;
        }

        #endregion

        #region ICanDrag Members

        public bool CanDrag()
        {
            return _canDrag;
        }

        #endregion

        #region IRequiresStorage Members

        public void GetStorage(Storage storage)
        {
            _storage = storage;
            string settingsPath = System.IO.Path.Combine(storage.StorageDirectory.FullName,"Settings.xml");
            _settings = Serializer.Load<Settings>("Webnet",settingsPath);
        }

        public void SaveState()
        {
            string settingsPath = System.IO.Path.Combine(_storage.StorageDirectory.FullName,"Settings.xml");
            Serializer.Save<Settings>("Webnet", _settings, settingsPath);
        }

        #endregion
    }
}